package com.mantru.iotpot.modbus;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;


public class Ymodem {

    public static final int SOH = 0x01;
    public static final int STX = 0x02;
    public static final int EOT = 0x04;
    public static final int ACK = 0x06;
    public static final int NAK = 0x15;
    public static final int CRC_MODE = 0x43;
    private static final int READ_TIMEOUT = 5000; // 5 seconds
    private final  BlockingQueue<Integer> responseQueue;

    // 构造函数：允许外部传入自定义的队列
    public Ymodem(BlockingQueue<Integer> queue) {
        this.responseQueue = queue != null ? queue : new LinkedBlockingQueue<>();
    }

    public Ymodem() {
        this.responseQueue = new LinkedBlockingQueue<>();
    }


    public byte[] waitForResponse(int expectedLength, long timeout) throws InterruptedException, IOException {
        long startTime = System.currentTimeMillis();
        byte[] response = new byte[expectedLength];
        int bytesRead = 0;
        while (bytesRead < expectedLength) {
            if (System.currentTimeMillis() - startTime >= timeout) {
                return null;
            }

            int responseByte = this.responseQueue.poll(READ_TIMEOUT, TimeUnit.MILLISECONDS);
            response[bytesRead] = (byte) responseByte;
            bytesRead++;
        }
        return response;
    }

    public void y_onDataCacheClear() {
        this.responseQueue.clear();
    }
    public void y_onDataReceive(byte[] data, int size) {
        for (int i = 0; i < size; i++) {
            this.responseQueue.add(data[i] & 0xFF);
        }
    }

    public static byte[] sendFileInfoPacket(String fileName, long fileSize, int fileCRC) throws IOException {
        // 构造文件信息包
        byte[] buffer = new byte[128];
        ByteArrayOutputStream packet = new ByteArrayOutputStream();
        packet.write((byte) SOH); // SOH
        packet.write((byte) 0x00); // 包号0
        packet.write((byte) 0xFF); // 补码0xFF

        // 文件名编码为ASCII
        byte[] fileNameBytes = fileName.getBytes("ASCII");
        System.arraycopy(fileNameBytes, 0, buffer, 0, fileNameBytes.length);
        System.arraycopy(new byte[]{0}, 0, buffer, fileNameBytes.length, 1);
        // 文件大小编码为BCD码
        byte[] fileSizeBytes = Long.toString(fileSize).getBytes("ASCII");
        System.arraycopy(fileSizeBytes, 0, buffer, fileNameBytes.length+1, fileSizeBytes.length);
        System.arraycopy(new byte[]{0}, 0, buffer, fileNameBytes.length, 1);

        byte[] crcBytes = new byte[2];
        crcBytes[0] = (byte)(fileCRC>>8);
        crcBytes[1] = (byte)(fileCRC&0xFF);

        System.arraycopy(crcBytes, 0, buffer, fileNameBytes.length+1+fileSizeBytes.length+1, crcBytes.length);
        packet.write(buffer);

        // 填充0x00到1024字节
        int remaining = 128 - packet.size();
        for (int i = 0; i < remaining; i++) {
            packet.write((byte) 0x00);
        }



        // 计算CRC16校验
        CRC16 crc = new CRC16();
        int crcValue = CRC16.CRC16_XMODEM(buffer);
        packet.write((byte)(crcValue>>8));
        packet.write((byte)(crcValue&0xFF));

        //释放内存
        fileNameBytes = null;
        fileSizeBytes = null;
        buffer = null;
        crcBytes = null;

        return packet.toByteArray();
    }


    public static byte[] sendDataPacket(int packetType, int packetNumber, byte[] buffer) {
        //packetNumber  是在1-254之间重复用
        if (packetNumber >= 255) {
            packetNumber = packetNumber % 254;
            if (packetNumber == 0)
                packetNumber = 254;
        }
        ByteArrayOutputStream packet = new ByteArrayOutputStream();
        packet.write(packetType);
        packet.write(packetNumber);
        packet.write((byte) (0xFF - packetNumber));
        packet.write(buffer, 0, buffer.length);


        CRC16 crc = new CRC16();
        int crcValue = CRC16.CRC16_XMODEM(buffer);
        packet.write((byte)(crcValue>>8));
        packet.write((byte)(crcValue&0xFF));

        return packet.toByteArray();
    }

    public static byte[] sendEndPacket() {
        // 构造结束帧
        ByteArrayOutputStream packet = new ByteArrayOutputStream();
        byte[] buffer = new byte[128];
        packet.write((byte) 0x01); // SOH
        packet.write((byte) 0x00); // 包号0
        packet.write((byte) 0xFF); // 补码0xFF
        // 数据部分全为0x1A
        for (int i = 0; i < 128; i++) {
            buffer[i] = 0;
        }
        packet.write(buffer, 0, buffer.length);
        // 计算CRC16校验
        CRC16 crc = new CRC16();
        int crcValue = CRC16.CRC16_XMODEM(buffer);
        packet.write((byte)(crcValue>>8));
        packet.write((byte)(crcValue&0xFF));
        buffer = null;
        return packet.toByteArray();
    }

    private static byte[] longToBCD(long value) {
        byte[] bcd = new byte[4];
        bcd[0] = (byte) ((value >> 24) & 0xFF);
        bcd[1] = (byte) ((value >> 16) & 0xFF);
        bcd[2] = (byte) ((value >> 8) & 0xFF);
        bcd[3] = (byte) (value & 0xFF);
        return bcd;
    }

}